﻿using System;
using System.Text.RegularExpressions;
using Com.JunCaiSoft.Common.AssistClass;

namespace Com.JunCaiSoft.Common.Verification
{
    public class SocialCreditCode
    {
        private SocialCreditCode(String inputSocialCreditCode)
        {
            socialCreditCode = inputSocialCreditCode;
        }
        public static string CheckSocialCreditCode(string inputSocialCreditCode, bool computeSocialCreditCode = false)
        {
            if (inputSocialCreditCode == "")
            {
                throw new Exception("社会统一信用代码不允许为空！");
            }
            if (inputSocialCreditCode.EndsWith("?") || inputSocialCreditCode.StartsWith("?"))
            {
                throw new Exception("不允许添加非法字符！");
            }
            if (inputSocialCreditCode.Length < 15 || inputSocialCreditCode.Length == 16 || inputSocialCreditCode.Length > 18 || (inputSocialCreditCode.Length == 17 && !computeSocialCreditCode))
            {
                throw new Exception("您输入的统一社会信用代码位数不正确！");
            }
            if (inputSocialCreditCode.Length == 15)
            {
                inputSocialCreditCode = "??" + inputSocialCreditCode + "?";
            }
            else if (inputSocialCreditCode.Length == 17 && computeSocialCreditCode)
            {
                inputSocialCreditCode += "?";
            }
            new SocialCreditCode(inputSocialCreditCode);
            return socialCreditCode;
        }
        //private static void RegularExpression()
        //{
        //    if (!Regex.IsMatch(socialCreditCode, @"(^\d|[A-GY?]{1}[1239?]{1}[1-8]{1}[1-7]{1}[1-9]{4}\d|[A-Z]{9}\d|[A-Z?]{1}$)"))
        //    {
        //        throw new Exception("输入的社会统一信用代码有误！");
        //    }
        //}
        private static String registPartmentCode { get; set; }
        private static void registPartmentCodeCheck()
        {
            if (registPartmentCode == "?")
            {
                return;
            }

            if (registPartmentCode.Length <= 1)
            {
                var a = ASCIIExchange.Asc(registPartmentCode);
                if (a > 47 && a < 58 || (a > 64 && a < 72 || a == 89))
                {
                    registPartmentCode = registPartmentCode;
                }
                else
                {
                    throw new Exception("登记部门号码有误！");
                }
            }
            else
            {
                throw new Exception("位数过多");
            }
        }
        private static String partmentClassCode { get; set; }
        private static void partmentClassCodeCheck()
        {
            if (partmentClassCode.Length > 1)
            {
                throw new Exception("机构类别代码位数有误！");
            }

            if (partmentClassCode == "?")
            {
                return;
            }

            if (registPartmentCode == "1" || registPartmentCode == "5" || registPartmentCode == "9")
            {
                if (partmentClassCode == "1" || partmentClassCode == "2" || partmentClassCode == "3" || partmentClassCode == "9")
                {
                    partmentClassCode = partmentClassCode;
                }
                else
                {
                    throw new Exception("机构类别代码有误！");
                }
            }
            else if (
                registPartmentCode == "2" ||
                registPartmentCode == "3" ||
                registPartmentCode == "4" ||
                registPartmentCode == "6" ||
                registPartmentCode == "7" ||
                registPartmentCode == "8" ||
                registPartmentCode == "A" ||
                registPartmentCode == "B" ||
                registPartmentCode == "C" ||
                registPartmentCode == "D" ||
                registPartmentCode == "E" ||
                registPartmentCode == "F" ||
                registPartmentCode == "G" ||
                registPartmentCode == "Y")
            {
                if (partmentClassCode == "1")
                {
                    partmentClassCode = partmentClassCode;
                }
                else
                {
                    throw new Exception("机构类别代码有误！");
                }
            }
        }
        private static string administrativeDivisionCode { get; set; }
        //做一个全国行政区域代码查找类，赋值之前必须要通过校验，必须符合中华人民共和国行政区划代码》（GB/T2260-2007)和《县以下行政区划代码编制规则》（GB/T10114-2003)。
        private static void administrativeDivisionCodeCheck()
        {
            if (administrativeDivisionCode.Length != 6)
            {
                throw new Exception("行政区域代码位数不正确！");
            }

            if (!Regex.IsMatch(administrativeDivisionCode, @"(^\d{6}$)"))
            {
                throw new Exception("行政区域代码不正确！");
            }
        }
        private static string orgnizationCode { get; set; }
        //组织机构代码证号，做一个组织机构代码证校验类，赋值之前必须符合国家标准GB11714《全国组织机构代码编制规则》编制
        private static void orgnizationCodeCheck()
        {
            if (orgnizationCode.Length != 9)
            {
                throw new Exception("组织机构代码位数不正确！");
            }
            var orgnization = orgnizationCode.Substring(0, 8);
            var orgnizationCheckCode = orgnizationCode.Substring(8, 1);
            int sum = 0;
            for (int i = 0; i < orgnization.Length; i++)
            {
                sum += OrgnizationCode(orgnization.Substring(i, 1), i + 1);
            }
            var computeResult = 11 - sum % 11;
            string resultChar = null;
            if (computeResult == 10)
            {
                resultChar = "X";
            }
            else if (computeResult == 11)
            {
                resultChar = "0";
            }
            else
            {
                resultChar = OrgnizationResultChange(computeResult);
            }
            if (resultChar == orgnizationCheckCode)
            {
                orgnizationCode = orgnizationCode;
            }
            else
            {
                throw new Exception("组织机构代码错误！");
            }
        }
        private static string checkCode { get; set; }
        private static void checkCodeCheck()
        {
            if (checkCode.Length > 1)
            {
                throw new Exception("校验码位数不正确！");
            }

            if (checkCode == "?")
            {
                return;
            }

            var str = registPartmentCode + partmentClassCode + administrativeDivisionCode + orgnizationCode;
            int sum = 0;
            for (int i = 0; i < str.Length; i++)
            {
                sum += SocialCreditCodeComputeLevel(str.Substring(i, 1), i + 1);
            }
            var result = 31 - sum % 31;
            string resultChar = null;
            if (result == 30)
            {
                resultChar = "Y";
            }
            else if (result == 31)
            {
                resultChar = "0";
            }
            else
            {
                resultChar = SocialCreditResultChange(result);
            }

            if (resultChar == checkCode)
            {
                checkCode = checkCode;
            }
            else if (checkCode == "?")
            {
                checkCode = resultChar;
            }
            else
            {
                throw new Exception("社会统一信用代码错误！");
            }
        }
        private static string socialCreditCode
        {
            get
            {
                registPartmentCodeCheck();
                partmentClassCodeCheck();
                administrativeDivisionCodeCheck();
                orgnizationCodeCheck();
                checkCodeCheck();

                var resultStr = registPartmentCode + partmentClassCode + administrativeDivisionCode + orgnizationCode + checkCode;
                return resultStr.Replace("?", null);
            }
            set
            {
                registPartmentCode = value.Substring(0, 1);
                partmentClassCode = value.Substring(1, 1);
                administrativeDivisionCode = value.Substring(2, 6);
                orgnizationCode = value.Substring(8, 9);
                checkCode = value.Substring(17, 1);
            }
        }
        private static int SocialCreditCodeComputeLevel(string input, int position)
        {
            if (input.Length > 1)
            {
                throw new Exception("传入字符位数不对！");
            }
            int rights;
            switch (position)
            {
                case 1: rights = 1; break;
                case 2: rights = 3; break;
                case 3: rights = 9; break;
                case 4: rights = 27; break;
                case 5: rights = 19; break;
                case 6: rights = 26; break;
                case 7: rights = 16; break;
                case 8: rights = 17; break;
                case 9: rights = 20; break;
                case 10: rights = 29; break;
                case 11: rights = 25; break;
                case 12: rights = 13; break;
                case 13: rights = 8; break;
                case 14: rights = 24; break;
                case 15: rights = 10; break;
                case 16: rights = 30; break;
                case 17: rights = 28; break;
                default: rights = 0; break;
            }
            return SocialCreditCharChange(input) * rights;
        }
        private static int OrgnizationCode(string input, int position)
        {
            if (input.Length > 1)
            {
                throw new Exception("传入字符位数不对！");
            }
            int rights;
            switch (position)
            {
                case 1: rights = 3; break;
                case 2: rights = 7; break;
                case 3: rights = 9; break;
                case 4: rights = 10; break;
                case 5: rights = 5; break;
                case 6: rights = 8; break;
                case 7: rights = 4; break;
                case 8: rights = 2; break;
                default: rights = 0; break;
            }
            return OrgnizationCharChange(input) * rights;
        }
        private static string SocialCreditResultChange(int inputNum)
        {
            var a = inputNum + 55;
            if (a > 64 && a < 73)
            {
                return (ASCIIExchange.Chr(inputNum + 55));
            }
            else if (inputNum + 56 > 73 && inputNum + 56 < 79)
            {
                return (ASCIIExchange.Chr(inputNum + 56));
            }
            else if (inputNum + 57 > 79 && inputNum + 57 < 83)
            {
                return (ASCIIExchange.Chr(inputNum + 57));
            }
            else if (inputNum + 58 > 83 && inputNum + 58 < 86)
            {
                return (ASCIIExchange.Chr(inputNum + 58));
            }
            else if (inputNum + 60 > 86 && inputNum + 60 < 90)
            {
                return (ASCIIExchange.Chr(inputNum + 60));
            }
            else if (inputNum + 48 > 47 && inputNum + 48 < 58)
            {
                return inputNum.ToString();
            }
            else
            {
                throw new Exception("输入字符错误！");
            }
        }
        private static int SocialCreditCharChange(string input)
        {
            var a = ASCIIExchange.Asc(input.ToUpper());
            if (a > 64 && a < 73)
            {
                return a - 55;
            }
            else if (a > 73 && a < 79)
            {
                return a - 56;
            }
            else if (a > 79 && a < 83)
            {
                return a - 57;
            }
            else if (a > 83 && a < 86)
            {
                return a - 58;
            }
            else if (a > 86 && a < 90)
            {
                return a - 59;
            }
            else if (a > 47 && a < 58)
            {
                return Int32.Parse(input);
            }
            else
            {
                throw new Exception("输入字符错误！");
            }
        }
        private static string OrgnizationResultChange(int inputNum)
        {
            var a = inputNum + 55;
            if (a > 64 && a < 91)
            {
                return (ASCIIExchange.Chr(inputNum + 55));
            }
            else if (inputNum + 48 > 47 && inputNum + 48 < 58)
            {
                return inputNum.ToString();
            }
            else
            {
                throw new Exception("输入字符错误！");
            }
        }
        private static int OrgnizationCharChange(string input)
        {
            var a = ASCIIExchange.Asc(input.ToUpper());
            if (a > 64 && a < 91)
            {
                return ASCIIExchange.Asc(input) - 55;
            }
            else if (a > 47 && a < 58)
            {
                return Int32.Parse(input);
            }
            else
            {
                throw new Exception("输入字符错误！");
            }
        }
    }
}
